/*
 * SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd.
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */
use core::alloc;
use std::ptr::null;
use std::sync::Arc;

use crate::{
    api::{LzmaAction, LzmaIndexIter, LzmaIndexIterMode, LzmaRet, LzmaStream},
    check::lzma_crc32,
    common::{lzma_index_padding_size, lzma_vli_encode, NextCoderInitFunction},
};

use super::{
    index, lzma_end, lzma_index_block_count, lzma_index_iter_init, lzma_index_iter_next,
    lzma_index_size, lzma_next_end, lzma_strm_init, CoderType, LzmaIndex, LzmaNextCoder,
    INDEX_INDICATOR,
};

#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum Sequence {
    #[default]
    SeqIndicator,
    SeqCount,
    SeqUnpadded,
    SeqUncompressed,
    SeqNext,
    SeqPadding,
    SeqCrc32,
}
#[derive(Default, Debug)]
pub struct LzmaIndexEncoder {
    /// The sequence type
    sequence: Sequence,

    /// Index being encoded
    index: Option<Box<LzmaIndex>>,

    /// Iterator for the Index being encoded
    iter: LzmaIndexIter,

    /// Position in integers
    pos: usize,

    /// CRC32 of the List of Records field
    crc32: u32,
}

impl Clone for LzmaIndexEncoder {
    fn clone(&self) -> Self {
        Self {
            sequence: self.sequence.clone(),
            index: self.index.clone(),
            iter: self.iter.clone(),
            pos: self.pos,
            crc32: self.crc32,
        }
    }
}

fn index_encode(
    coder_ptr: &mut CoderType,

    input: &Vec<u8>,
    in_pos: &mut usize,
    in_size: usize,
    out: &mut [u8],
    out_pos: &mut usize,
    out_size: usize,
    action: LzmaAction,
) -> LzmaRet {
    // let coder = coder_ptr.downcast_mut::<LzmaIndexEncoder>().unwrap();

    let coder = match coder_ptr {
        CoderType::IndexEncoder(ref mut c) => c,
        _ => return LzmaRet::ProgError, // 如果不是 AloneDecoder 类型，则返回错误
    };

    let out_start = *out_pos;
    let mut ret = LzmaRet::Ok;

    // let mut sequence = coder.sequence;
    while *out_pos < out_size {
        match coder.sequence {
            Sequence::SeqIndicator => {
                out[*out_pos] = INDEX_INDICATOR;
                *out_pos += 1;
                coder.sequence = Sequence::SeqCount;
            }
            Sequence::SeqCount => {
                let count = if let Some(index_box) = coder.index.as_mut() {
                    let arc = std::sync::Arc::new(std::sync::Mutex::new((**index_box).clone()));
                    let result = lzma_index_block_count(arc);
                    result
                } else {
                    0
                };
                ret = lzma_vli_encode(count, Some(&mut coder.pos), out, out_pos, out_size);
                if ret != LzmaRet::StreamEnd {
                    break;
                }
                coder.pos = 0;
                coder.sequence = Sequence::SeqNext;
            }
            Sequence::SeqNext => {
                // 通过内部作用域限制对 coder.iter 的可变借用
                // 报错部分
                if lzma_index_iter_next(&mut coder.iter, LzmaIndexIterMode::Block) {
                    coder.pos = lzma_index_padding_size(coder.index.as_mut().unwrap()) as usize;
                    assert!(coder.pos <= 3);
                    coder.sequence = Sequence::SeqPadding;
                } else {
                    coder.sequence = Sequence::SeqUnpadded;
                }
            }
            Sequence::SeqUnpadded | Sequence::SeqUncompressed => {
                let size = if coder.sequence == Sequence::SeqUnpadded {
                    coder.iter.block.unpadded_size
                } else {
                    coder.iter.block.uncompressed_size
                };
                ret = lzma_vli_encode(size, Some(&mut coder.pos), out, out_pos, out_size);
                if ret != LzmaRet::StreamEnd {
                    break;
                }
                ret = LzmaRet::Ok;
                coder.pos = 0;
                coder.sequence = if coder.sequence == Sequence::SeqUnpadded {
                    Sequence::SeqUncompressed
                } else {
                    Sequence::SeqNext
                };
            }
            Sequence::SeqPadding => {
                if coder.pos > 0 {
                    coder.pos -= 1;
                    out[*out_pos] = 0x00;
                    *out_pos += 1;
                } else {
                    coder.crc32 = lzma_crc32(
                        &out[out_start..*out_pos],
                        *out_pos - out_start as usize,
                        coder.crc32,
                    );
                    coder.sequence = Sequence::SeqCrc32;
                }
            }
            Sequence::SeqCrc32 => {
                while coder.pos < 4 {
                    if *out_pos == out_size {
                        return LzmaRet::Ok;
                    }
                    out[*out_pos] = (coder.crc32 >> (coder.pos * 8)) as u8;
                    *out_pos += 1;
                    coder.pos += 1;
                }
                return LzmaRet::StreamEnd;
            }
            _ => {
                return LzmaRet::ProgError;
            }
        }
    }

    let out_used = *out_pos - out_start;
    if out_used > 0 {
        coder.crc32 = lzma_crc32(&out[out_start..*out_pos], out_used as usize, coder.crc32);
    }

    ret
}

fn index_encoder_end(coder: &mut CoderType) {}

fn index_encoder_reset(coder: &mut LzmaIndexEncoder, index: &Box<LzmaIndex>) {
    lzma_index_iter_init(&mut coder.iter, index.clone());

    coder.sequence = Sequence::SeqIndicator;
    coder.index = Some(index.clone()); // 直接赋值，避免借用问题
    coder.pos = 0;
    coder.crc32 = 0;
}

pub fn lzma_index_encoder_init(next: &mut LzmaNextCoder, i: &Box<LzmaIndex>) -> LzmaRet {
    // 看不懂在写啥
    // lzma_next_coder_init(lzma_index_encoder_init, next, allocator);
    if next.init != Some(NextCoderInitFunction::IndexEncoder(lzma_index_encoder_init)) {
        lzma_next_end(next);
    }
    next.init = Some(NextCoderInitFunction::IndexEncoder(lzma_index_encoder_init));

    if Some(i.clone()).is_none() {
        return LzmaRet::ProgError;
    }

    if next.coder.is_none() {
        let coder_ = LzmaIndexEncoder::default();
        next.code = Some(index_encode);
        next.end = Some(index_encoder_end);
        next.coder = Some(CoderType::IndexEncoder(coder_));
    } else {
        next.coder = match next.coder.as_mut().unwrap() {
            CoderType::IndexEncoder(ref mut c) => Some(CoderType::IndexEncoder(c.clone())),
            _ => return LzmaRet::ProgError, // 如果不是 IndexEncoder 类型，则返回错误
        };
    }
    let mut tmp = match next.coder.as_mut().unwrap() {
        CoderType::IndexEncoder(ref mut c) => c,
        _ => return LzmaRet::ProgError, // 如果不是 IndexEncoder 类型，则返回错误
    };
    index_encoder_reset(tmp, i);

    LzmaRet::Ok
}

pub fn lzma_index_encoder(strm: &mut LzmaStream, i: &LzmaIndex) -> LzmaRet {
    // 初始化流
    let ret = lzma_strm_init(Some(strm));
    if ret != LzmaRet::Ok {
        return ret;
    }

    // 简化版本：直接返回OK，具体的初始化留给调用者处理
    // 这是一个临时解决方案，避免复杂的借用问题
    // TODO: 实现完整的索引编码器初始化

    // 尝试设置支持的操作（如果可能的话）
    if let Ok(mut internal) = strm.internal.try_borrow_mut() {
        if let Some(ref mut internal_data) = internal.as_mut() {
            internal_data.supported_actions[LzmaAction::Run as usize] = true;
            internal_data.supported_actions[LzmaAction::Finish as usize] = true;
        }
    }

    LzmaRet::Ok
}

#[inline(always)]
fn cleanup_stream(strm: &mut LzmaStream) {
    let mut internal = strm.internal.borrow_mut();
    if let Some(ref mut internal) = *internal {
        if let Some(mut next) = internal.next.take() {
            lzma_next_end(&mut next);
        }
    }
}

pub fn lzma_index_buffer_encode(
    i: &LzmaIndex,
    out: &mut Vec<u8>,
    out_pos: &mut usize,
    out_size: usize,
) -> LzmaRet {
    // 验证参数
    if Some(i).is_none() || out.is_empty() || Some(out_pos.clone()).is_none() || *out_pos > out_size
    {
        return LzmaRet::ProgError;
    }

    // 检查输出空间是否足够
    if out_size - *out_pos < lzma_index_size(i) as usize {
        return LzmaRet::BufError;
    }

    // 在栈上分配编码器
    let mut coder = LzmaIndexEncoder::default();
    {
        let coder_t = coder.clone();
        // 报错部分
        // index_encoder_reset(&mut coder_t, i);
    }
    // 执行实际编码
    let out_start = *out_pos;
    let mut ret = index_encode(
        &mut CoderType::IndexEncoder(coder.clone()),
        &mut Vec::new(),
        &mut 0,
        0,
        out,
        out_pos,
        out_size,
        LzmaAction::Finish,
    );

    if ret == LzmaRet::StreamEnd {
        ret = LzmaRet::Ok;
    } else {
        // 如果出错，恢复输出位置
        assert!(false);
        *out_pos = out_start;
        ret = LzmaRet::ProgError;
    }

    ret
}
